import transaction
import numpy
import copy


class system:
    shardNum = 0
    txPool = []
    tps = 0
    pcn = []
    allow = 1
    epoach = 0

    def __init__(self, snum, pcn, sTxs, tps):
        self.shardNum = snum
        self.tps = tps
        self.allow = 1

        for i in range(len(pcn)):
            self.pcn.append(pcn[i])
        for i in range(len(sTxs)):
            self.txPool.append(sTxs[i])

        print("sign 1: len(self.pcn) = %d; len(self.pcn[1]) = %d" % (len(self.pcn), len(self.pcn[0])))
        print("sign 2: len(self.txPool) = %d" % (len(self.txPool)))


def check(txPool):
    for shard in txPool:
        if len(shard) != 0:
            return 1
    return 0


# isAllow 表示是否允许链下交易处理 1-允许，0-不允许
def tx_exec(node_num, snum, path, txs, ledger_tps, pcn_tps, ch_life, isAllow=0):
    epoch = 0
    tx_pool = copy.deepcopy(txs)
    final_pool = [0 for _ in range(snum)]

    while check(tx_pool):
        # 记录本次刷新的pcn_tps
        ch_tps = pcn_tps

        '''
        if (epoch%10 == 0):
            print("epoch = ", epoch)
            for i in range(len(txPool)):
                print("\tshard %d = %d" % (i ,len(txPool[i])))
        '''

        # 对每个分片分别处理
        for index in range(len(tx_pool)):
            # 如果可以处理就直接处理完
            l = len(tx_pool[index])
            if l < ledger_tps:
                tx_pool[index] = []
                continue

            n = 0
            l -= 1
            while n < ledger_tps:
                is_off = 0

                # 如果该分片交易池不为空，处理一笔交易
                if l >= 0:
                    tx = tx_pool[index][l].copy()

                    # if (n < 4):
                    #   print("tx.s = %d; tx.r = %d" % (tx[0], tx[1]))
                    # print("len(pcn) = %d; len(pcn[1]) = %d" % (len(self.pcn), len(self.pcn[1])))

                    # 可进行链下处理时不需要消耗区块链的tps
                    if isAllow and 0 < path[tx[0]][tx[1]] < ch_tps:
                        ch_tps -= path[tx[0]][tx[1]]
                        is_off = 1

                    # 如果该交易没有在链下处理，且是跨分片交易，增加新的待处理交易并添加到交易池中
                    if is_off != 1 and tx[0] % snum != tx[1] % snum:
                        sid = tx[1] % snum
                        tx_pool[sid].insert(0, [tx[1], tx[1], 1])
                        if sid == index:
                            l += 1

                    l -= 1
                    tx_pool[index].pop()
                else:
                    tx_pool[index] = []
                    break

                if is_off != 1:
                    n += 1

        # 根据本轮tps的消耗增加需要处理的交易，然后将其添加进交易池
        add_num = int((pcn_tps - ch_tps) // ch_life + 1)*3
        add_txs = transaction.generate_patch_tx(node_num, add_num)
        for tx in add_txs:
            sid1 = tx[0]%snum
            sid2 = tx[1]%snum

            # final_pool[sid].append(tx)
            final_pool[sid1] += 1
            if sid1 != sid2:
                final_pool[sid2] += 1
        '''
        '''

        # 计时器+1
        epoch += 1

        if epoch % 1000 == 0:
            print("第", epoch, "周期已完成")

    # 计算通道交易的处理时间
    if isAllow:
        final_cost = [(tx_num//ledger_tps + 1) for tx_num in final_pool]
        epoch += max(final_cost)

    return epoch
